# -*- coding: utf-8 -*-

from odoo import http
from odoo.http import request
from .main import api_response, validate_token, require_admin, check_activity_permission
from .auth import AuthController
import logging

_logger = logging.getLogger(__name__)


class ActivityController(http.Controller):
    
    def _get_full_url(self, url):
        """将相对URL转换为完整URL"""
        if not url:
            return ''
        # 替换内部域名为外部域名
        if url.startswith('http://odoo'):
            url = url.replace('http://odoo', 'https://naturedao.tech')
            return url
        # 已经是完整的外部URL
        if url.startswith('https://'):
            return url
        # 使用固定的外部域名
        base_url = 'https://naturedao.tech'
        # 如果是相对路径，加上base URL
        if url.startswith('/'):
            return f'{base_url}{url}'
        return url

    @http.route('/api/v1/activities', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors='*')
    def activities(self, status=None, page=1, page_size=10, keyword=None, **kwargs):
        """获取活动列表 / 创建活动"""
        try:
            if request.httprequest.method == 'GET':
                # 尝试验证token（可选）
                token = request.httprequest.headers.get('Authorization', '').replace('Bearer ', '')
                _logger.info(f'🔍 GET /activities: status={status}, page={page}, token={token[:20] if token else "无"}...')
                
                if token:
                    user = request.env['wechat.user'].sudo().search([('token', '=', token)], limit=1)
                    if user and user.check_token(token):
                        request.wechat_user = user
                        _logger.info(f'💚 Token验证成功: 用户={user.name}')
                
                # 获取活动列表
                domain = [('status', 'in', ['unpublished', 'ongoing', 'finished'])]
                
                if status:
                    domain.append(('status', '=', status))
                
                if keyword:
                    domain.append(('title', 'ilike', keyword))
                
                page = int(page) if page else 1
                page_size = int(page_size) if page_size else 10
                offset = (page - 1) * page_size
                
                _logger.info(f'📋 查询活动: domain={domain}, page={page}, page_size={page_size}')
                
                activities = request.env['speech.activity'].sudo().search(
                    domain, limit=page_size, offset=offset, order='create_date desc'
                )
                
                total = request.env['speech.activity'].sudo().search_count(domain)
                
                _logger.info(f'📊 找到 {len(activities)} 条活动，总数={total}')
                
                items = []
                for activity in activities:
                    # 检查当前用户是否可以管理
                    can_manage = False
                    if hasattr(request, 'wechat_user'):
                        can_manage = activity.can_user_manage(request.wechat_user)
                    
                    items.append({
                        'id': activity.id,
                        'title': activity.title,
                        'description': activity.description,
                        'rules': activity.rules,
                        'start_time': activity.start_time.strftime('%Y-%m-%d %H:%M:%S') if activity.start_time else '',
                        'end_time': activity.end_time.strftime('%Y-%m-%d %H:%M:%S') if activity.end_time else '',
                        'registration_start_time': activity.registration_start_time.strftime('%Y-%m-%d %H:%M:%S') if activity.registration_start_time else '',
                        'registration_end_time': activity.registration_end_time.strftime('%Y-%m-%d %H:%M:%S') if activity.registration_end_time else '',
                        'voting_enabled': activity.voting_enabled,
                        'voting_start_time': activity.voting_start_time.strftime('%Y-%m-%d %H:%M:%S') if activity.voting_start_time else '',
                        'voting_end_time': activity.voting_end_time.strftime('%Y-%m-%d %H:%M:%S') if activity.voting_end_time else '',
                        'max_votes_per_user': activity.max_votes_per_user,
                        'status': activity.status,
                        'registration_count': activity.registration_count,
                        'vote_count': activity.vote_count,
                        'creator_name': activity.creator_id.name if activity.creator_id else '',
                        'can_manage': can_manage,
                    })
                
                _logger.info(f'✅ 返回 {len(items)} 条活动数据')
                
                return request.make_json_response(api_response(True, {
                    'items': items,
                    'total': total,
                    'page': page,
                    'page_size': page_size,
                    'has_more': total > page * page_size
                }))
            
            elif request.httprequest.method == 'POST':
                # 创建活动（需要登录）
                # 手动验证token
                token = request.httprequest.headers.get('Authorization', '').replace('Bearer ', '')
                
                if not token:
                    return api_response(False, message='请先登录', code=401)
                
                user = request.env['wechat.user'].sudo().search([('token', '=', token)], limit=1)
                
                if not user or not user.check_token(token):
                    return api_response(False, message='登录已过期，请重新登录', code=401)
                
                request.wechat_user = user
                
                _logger.info(f'用户 {user.name} (ID:{user.id}) 正在创建活动')
                
                # 从Body读取数据（Odoo type='json'不会自动映射参数）
                import json
                body_data = request.httprequest.get_data(as_text=True)
                data = json.loads(body_data) if body_data else {}
                
                _logger.info(f'接收到的数据: title={data.get("title")}, description={data.get("description")}')
                
                # 构建创建数据
                create_vals = {
                    'title': data.get('title'),
                    'description': data.get('description', ''),
                    'rules': data.get('rules', ''),
                    'status': 'unpublished',
                    'creator_id': request.wechat_user.id,
                }
                
                # 联系人信息
                if data.get('contact_name'):
                    create_vals['contact_name'] = data.get('contact_name')
                if data.get('contact_wechat'):
                    create_vals['contact_wechat'] = data.get('contact_wechat')
                if data.get('contact_phone'):
                    create_vals['contact_phone'] = data.get('contact_phone')
                
                # 地址信息
                if data.get('address'):
                    create_vals['address'] = data.get('address')
                if data.get('latitude'):
                    create_vals['latitude'] = data.get('latitude')
                if data.get('longitude'):
                    create_vals['longitude'] = data.get('longitude')
                
                # 时间字段（可选）
                if data.get('start_time'):
                    create_vals['start_time'] = data.get('start_time')
                if data.get('end_time'):
                    create_vals['end_time'] = data.get('end_time')
                if data.get('registration_start_time'):
                    create_vals['registration_start_time'] = data.get('registration_start_time')
                if data.get('registration_end_time'):
                    create_vals['registration_end_time'] = data.get('registration_end_time')
                
                # 加油相关
                if data.get('voting_enabled'):
                    create_vals['voting_enabled'] = True
                    if data.get('voting_start_time'):
                        create_vals['voting_start_time'] = data.get('voting_start_time')
                    if data.get('voting_end_time'):
                        create_vals['voting_end_time'] = data.get('voting_end_time')
                    if data.get('max_votes_per_user'):
                        create_vals['max_votes_per_user'] = data.get('max_votes_per_user')
                else:
                    create_vals['voting_enabled'] = False
                
                # 模板类型
                template_type = data.get('template_type', 'chinese')
                if template_type not in ['chinese', 'english']:
                    template_type = 'chinese'
                create_vals['template_type'] = template_type
                
                _logger.info(f'📝 提取的创建字段: {create_vals}')
                
                activity = request.env['speech.activity'].sudo().create(create_vals)
                
                # 自动创建报名项目（根据模板类型）
                request.env['activity.registration.item'].sudo().create_default_items(activity.id, template_type)
                
                _logger.info(f'✅ 会议创建成功: id={activity.id}, title={activity.title}, creator={request.wechat_user.name}')
                _logger.info(f'✅ 已创建16个默认报名项目')
                
                return request.make_json_response(api_response(True, {'id': activity.id}, '创建成功'))
                
        except Exception as e:
            _logger.error(f'❌ 活动操作失败: {str(e)}', exc_info=True)
            return request.make_json_response(api_response(False, message=f'操作失败: {str(e)}'))

    @http.route('/api/v1/activities/<int:activity_id>', type='http', auth='public', methods=['GET', 'PUT', 'DELETE'], csrf=False, cors='*')
    def activity_detail(self, activity_id, **kwargs):
        """获取/更新/删除活动详情"""
        try:
            activity = request.env['speech.activity'].sudo().browse(activity_id)
            
            if not activity.exists():
                _logger.warning(f'⚠️ 活动不存在: id={activity_id}')
                return request.make_json_response(api_response(False, message='活动不存在', code=404))
            
            if request.httprequest.method == 'GET':
                # 尝试验证token（可选，用于显示用户相关信息）
                token = request.httprequest.headers.get('Authorization', '').replace('Bearer ', '')
                _logger.info(f'🔍 GET /activities/{activity_id}: token={token[:20] if token else "无"}...')
                
                if token:
                    user = request.env['wechat.user'].sudo().search([('token', '=', token)], limit=1)
                    if user and user.check_token(token):
                        request.wechat_user = user
                        _logger.info(f'💚 Token验证成功: 用户={user.name}')
                
                # 检查用户是否已报名和已加油
                has_registered = False
                has_voted = False
                
                if hasattr(request, 'wechat_user'):
                    has_registered = bool(request.env['speech.registration'].sudo().search([
                        ('activity_id', '=', activity_id),
                        ('user_id', '=', request.wechat_user.id)
                    ], limit=1))
                    
                    has_voted = bool(request.env['speech.vote'].sudo().search([
                        ('activity_id', '=', activity_id),
                        ('user_id', '=', request.wechat_user.id)
                    ], limit=1))
                
                # 检查当前用户是否可以管理此活动
                can_manage = False
                if hasattr(request, 'wechat_user'):
                    can_manage = activity.can_user_manage(request.wechat_user)
                
                _logger.info(f'✅ 返回活动详情: title={activity.title}, status={activity.status}')
                
                return request.make_json_response(api_response(True, {
                    'id': activity.id,
                    'title': activity.title,
                    'description': activity.description,
                    'rules': activity.rules,
                    'contact_name': activity.contact_name or '',
                    'contact_wechat': activity.contact_wechat or '',
                    'contact_phone': activity.contact_phone or '',
                    'address': activity.address or '',
                    'latitude': activity.latitude or 0,
                    'longitude': activity.longitude or 0,
                    'start_time': activity.start_time.strftime('%Y-%m-%d %H:%M:%S') if activity.start_time else '',
                    'end_time': activity.end_time.strftime('%Y-%m-%d %H:%M:%S') if activity.end_time else '',
                    'registration_start_time': activity.registration_start_time.strftime('%Y-%m-%d %H:%M:%S') if activity.registration_start_time else '',
                    'registration_end_time': activity.registration_end_time.strftime('%Y-%m-%d %H:%M:%S') if activity.registration_end_time else '',
                    'voting_enabled': activity.voting_enabled,
                    'voting_start_time': activity.voting_start_time.strftime('%Y-%m-%d %H:%M:%S') if activity.voting_start_time else '',
                    'voting_end_time': activity.voting_end_time.strftime('%Y-%m-%d %H:%M:%S') if activity.voting_end_time else '',
                    'max_votes_per_user': activity.max_votes_per_user,
                    'status': activity.status,
                    'registration_count': activity.registration_count,
                    'vote_count': activity.vote_count,
                    'has_registered': has_registered,
                    'has_voted': has_voted,
                    'can_manage': can_manage,  # 是否可以管理
                    'creator_name': activity.creator_id.name if activity.creator_id else '',
                }))
            
            elif request.httprequest.method == 'PUT':
                # 更新活动（需要管理权限）
                # 手动验证token
                token = request.httprequest.headers.get('Authorization', '').replace('Bearer ', '')
                
                if not token:
                    return request.make_json_response(api_response(False, message='请先登录', code=401))
                
                user = request.env['wechat.user'].sudo().search([('token', '=', token)], limit=1)
                
                if not user or not user.check_token(token):
                    return request.make_json_response(api_response(False, message='登录已过期，请重新登录', code=401))
                
                request.wechat_user = user
                
                if not check_activity_permission(activity_id):
                    return request.make_json_response(api_response(False, message='您没有权限管理此活动', code=403))
                
                # 从Body读取数据
                import json
                body_data = request.httprequest.get_data(as_text=True)
                data = json.loads(body_data) if body_data else {}
                
                _logger.info(f'📝 PUT /activities/{activity_id}: 数据={data}')
                
                # 构建更新数据
                update_vals = {}
                
                if 'title' in data:
                    update_vals['title'] = data['title']
                if 'description' in data:
                    update_vals['description'] = data['description']
                if 'rules' in data:
                    update_vals['rules'] = data['rules']
                if 'start_time' in data:
                    update_vals['start_time'] = data['start_time']
                if 'end_time' in data:
                    update_vals['end_time'] = data['end_time']
                if 'registration_start_time' in data:
                    update_vals['registration_start_time'] = data['registration_start_time']
                if 'registration_end_time' in data:
                    update_vals['registration_end_time'] = data['registration_end_time']
                if 'voting_enabled' in data:
                    update_vals['voting_enabled'] = data['voting_enabled']
                if 'voting_start_time' in data:
                    update_vals['voting_start_time'] = data['voting_start_time']
                if 'voting_end_time' in data:
                    update_vals['voting_end_time'] = data['voting_end_time']
                if 'max_votes_per_user' in data:
                    update_vals['max_votes_per_user'] = data['max_votes_per_user']
                if 'status' in data:
                    update_vals['status'] = data['status']
                
                _logger.info(f'📝 提取的更新字段: {update_vals}')
                activity.sudo().write(update_vals)
                
                _logger.info(f'✅ 活动更新成功: id={activity_id}')
                
                return request.make_json_response(api_response(True, message='更新成功'))
            
            elif request.httprequest.method == 'DELETE':
                # 删除活动（需要管理权限）
                # 手动验证token
                token = request.httprequest.headers.get('Authorization', '').replace('Bearer ', '')
                
                _logger.info(f'🗑️ DELETE /activities/{activity_id}: token={token[:20] if token else "无"}...')
                
                if not token:
                    return request.make_json_response(api_response(False, message='请先登录', code=401))
                
                user = request.env['wechat.user'].sudo().search([('token', '=', token)], limit=1)
                
                if not user or not user.check_token(token):
                    return request.make_json_response(api_response(False, message='登录已过期，请重新登录', code=401))
                
                request.wechat_user = user
                
                if not check_activity_permission(activity_id):
                    return request.make_json_response(api_response(False, message='您没有权限删除此活动', code=403))
                
                activity.sudo().unlink()
                
                _logger.info(f'✅ 活动删除成功: id={activity_id}')
                
                return request.make_json_response(api_response(True, message='删除成功'))
                
        except Exception as e:
            _logger.error(f'❌ 活动详情操作失败: {str(e)}', exc_info=True)
            return request.make_json_response(api_response(False, message=f'操作失败: {str(e)}'))

    @http.route('/api/v1/activities/<int:activity_id>/publish', type='json', auth='public', methods=['POST'], csrf=False, cors='*')
    def publish_activity(self, activity_id, **kwargs):
        """发布活动（从draft到ongoing）"""
        try:
            # 验证token
            token = request.httprequest.headers.get('Authorization', '').replace('Bearer ', '')
            if not token:
                return api_response(False, message='请先登录', code=401)
            
            user = request.env['wechat.user'].sudo().search([('token', '=', token)], limit=1)
            if not user or not user.check_token(token):
                return api_response(False, message='登录已过期，请重新登录', code=401)
            
            request.wechat_user = user
            
            activity = request.env['speech.activity'].sudo().browse(activity_id)
            if not activity.exists():
                return api_response(False, message='活动不存在', code=404)
            
            # 检查权限
            if not activity.can_user_manage(request.wechat_user):
                return api_response(False, message='您没有权限发布此活动', code=403)
            
            # 更新状态为ongoing
            activity.sudo().write({'status': 'ongoing'})
            
            _logger.info(f'用户 {user.name} 发布了活动 {activity.title}')
            
            return api_response(True, message='活动已发布')
            
        except Exception as e:
            _logger.error(f'发布活动失败: {str(e)}')
            return api_response(False, message=f'发布失败: {str(e)}')

    @http.route('/api/v1/statistics', type='http', auth='public', methods=['GET'], csrf=False, cors='*')
    def global_statistics(self, **kwargs):
        """获取全局统计数据"""
        try:
            _logger.info(f'📊 GET /statistics')
            
            # 统计会议总数（不包括已取消）
            total_activities = request.env['speech.activity'].sudo().search_count([
                ('status', 'in', ['unpublished', 'ongoing', 'finished'])
            ])
            
            # 统计总报名数（使用新的项目报名模型）
            total_registrations = request.env['activity.item.registration'].sudo().search_count([])
            
            # 统计总加油数
            total_votes = request.env['speech.vote'].sudo().search_count([])
            
            _logger.info(f'✅ 返回统计: 会议={total_activities}, 报名={total_registrations}, 加油={total_votes}')
            
            return request.make_json_response(api_response(True, {
                'total_activities': total_activities,
                'total_registrations': total_registrations,
                'total_votes': total_votes,
            }))
            
        except Exception as e:
            _logger.error(f'❌ 获取统计失败: {str(e)}', exc_info=True)
            return request.make_json_response(api_response(False, message=f'获取失败: {str(e)}'))

    @http.route('/api/v1/activities/<int:activity_id>/statistics', type='http', auth='public', methods=['GET'], csrf=False, cors='*')
    def activity_statistics(self, activity_id):
        """获取活动统计"""
        try:
            _logger.info(f'📊 GET /activities/{activity_id}/statistics')
            
            activity = request.env['speech.activity'].sudo().browse(activity_id)
            
            if not activity.exists():
                _logger.warning(f'⚠️ 活动不存在: id={activity_id}')
                return request.make_json_response(api_response(False, message='活动不存在', code=404))
            
            _logger.info(f'✅ 返回统计: 报名={activity.registration_count}, 加油={activity.vote_count}')
            
            return request.make_json_response(api_response(True, {
                'registration_count': activity.registration_count,
                'approved_registration_count': activity.approved_registration_count,
                'vote_count': activity.vote_count,
            }))
            
        except Exception as e:
            _logger.error(f'❌ 获取统计失败: {str(e)}', exc_info=True)
            return request.make_json_response(api_response(False, message=f'获取失败: {str(e)}'))

    @http.route('/api/v1/activities/<int:activity_id>/wxacode', type='http', auth='public', methods=['GET'], csrf=False, cors='*')
    def generate_wxacode(self, activity_id):
        """生成微信小程序码"""
        try:
            _logger.info(f'📱 GET /activities/{activity_id}/wxacode')
            
            activity = request.env['speech.activity'].sudo().browse(activity_id)
            
            if not activity.exists():
                return request.make_json_response(api_response(False, message='会议不存在', code=404))
            
            # 获取access_token
            auth_controller = AuthController()
            access_token = auth_controller._get_wechat_access_token()
            
            if not access_token:
                _logger.error('❌ 获取access_token失败')
                return request.make_json_response(api_response(False, message='生成失败，请稍后重试'))
            
            # 调用微信生成小程序码接口
            import requests
            import json
            
            url = f'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={access_token}'
            
            # 使用scene参数传递activity_id
            data = {
                'scene': f'id={activity_id}',  # 会议ID作为scene参数
                'page': 'pages/activity/detail/detail',  # 不带参数
                'check_path': False,  # 不检查页面路径
                'env_version': 'release',  # 正式版（release=正式版, trial=体验版, develop=开发版）
                'width': 430
            }
            
            _logger.info(f'🔑 调用微信生成小程序码: scene={data["scene"]}')
            
            response = requests.post(url, json=data, timeout=10)
            
            # 检查返回类型
            content_type = response.headers.get('Content-Type', '')
            
            if 'image' in content_type:
                # 成功返回图片
                _logger.info(f'✅ 小程序码生成成功')
                return request.make_response(
                    response.content,
                    headers=[
                        ('Content-Type', 'image/jpeg'),
                        ('Content-Disposition', f'inline; filename=activity_{activity_id}_wxacode.jpg')
                    ]
                )
            else:
                # 返回错误信息
                result = response.json()
                _logger.error(f'❌ 生成小程序码失败: {result}')
                return request.make_json_response(api_response(False, message=result.get('errmsg', '生成失败')))
            
        except Exception as e:
            _logger.error(f'❌ 生成小程序码异常: {str(e)}', exc_info=True)
            return request.make_json_response(api_response(False, message=f'生成失败: {str(e)}'))

    @http.route('/api/v1/activities/<int:activity_id>/export', type='http', auth='public', methods=['GET'], csrf=False, cors='*')
    def export_activity_excel(self, activity_id, **kwargs):
        """导出会议及报名信息为Excel"""
        try:
            _logger.info(f'📊 GET /activities/{activity_id}/export')
            
            # 验证Token（支持Header和URL参数）
            token = request.httprequest.headers.get('Authorization', '').replace('Bearer ', '')
            if not token:
                token = kwargs.get('token', '')
            
            if not token:
                return request.make_json_response(api_response(False, message='请先登录', code=401))
            
            user = request.env['wechat.user'].sudo().search([('token', '=', token)], limit=1)
            
            if not user or not user.check_token(token):
                return request.make_json_response(api_response(False, message='登录已过期', code=401))
            
            # 检查是否是管理员
            activity = request.env['speech.activity'].sudo().browse(activity_id)
            if not activity.exists():
                return request.make_json_response(api_response(False, message='会议不存在', code=404))
            
            is_manager = user.id == activity.creator_id.id or user in activity.manager_ids
            
            if not is_manager:
                return request.make_json_response(api_response(False, message='权限不足，仅管理员可导出', code=403))
            
            # 生成Excel
            from io import BytesIO
            import xlsxwriter
            
            output = BytesIO()
            workbook = xlsxwriter.Workbook(output)
            
            # 设置格式
            title_format = workbook.add_format({
                'bold': True,
                'font_size': 14,
                'bg_color': '#4472C4',
                'font_color': 'white',
                'align': 'center',
                'valign': 'vcenter',
                'border': 1
            })
            
            header_format = workbook.add_format({
                'bold': True,
                'bg_color': '#D6DCE4',
                'align': 'center',
                'valign': 'vcenter',
                'border': 1
            })
            
            cell_format = workbook.add_format({
                'align': 'left',
                'valign': 'vcenter',
                'border': 1,
                'text_wrap': True
            })
            
            # Sheet 1: 会议基本信息
            ws_info = workbook.add_worksheet('会议信息')
            ws_info.write(0, 0, '会议标题', header_format)
            ws_info.write(0, 1, activity.title, cell_format)
            ws_info.write(1, 0, '会议描述', header_format)
            ws_info.write(1, 1, activity.description or '', cell_format)
            ws_info.write(2, 0, '开始时间', header_format)
            ws_info.write(2, 1, activity.start_time or '', cell_format)
            ws_info.write(3, 0, '结束时间', header_format)
            ws_info.write(3, 1, activity.end_time or '', cell_format)
            ws_info.write(4, 0, '报名时间', header_format)
            ws_info.write(4, 1, f'{activity.registration_start_time} ~ {activity.registration_end_time}', cell_format)
            ws_info.write(5, 0, '会议地址', header_format)
            ws_info.write(5, 1, activity.address or '', cell_format)
            ws_info.write(6, 0, '创建者', header_format)
            ws_info.write(6, 1, activity.creator_id.name if activity.creator_id else '', cell_format)
            ws_info.write(7, 0, '状态', header_format)
            status_dict = {'unpublished': '未发布', 'ongoing': '进行中', 'finished': '已结束'}
            ws_info.write(7, 1, status_dict.get(activity.status, activity.status), cell_format)
            
            ws_info.set_column(0, 0, 20)
            ws_info.set_column(1, 1, 60)
            
            # Sheet 2: 报名信息（按角色分类）
            ws_reg = workbook.add_worksheet('报名信息')
            
            # 标题行
            ws_reg.merge_range(0, 0, 0, 9, f'【{activity.title}】报名信息汇总', title_format)
            
            # 表头
            headers = ['角色分类', '项目名称', '姓名', '自我介绍', '演讲介绍', '报名照片', '风采照片1', '风采照片2', '风采照片3', '状态']
            for col, header in enumerate(headers):
                ws_reg.write(1, col, header, header_format)
            
            # 数据
            row = 2
            categories = request.env['item.role.category'].sudo().search([], order='sequence')
            
            for category in categories:
                items = request.env['activity.registration.item'].sudo().search([
                    ('activity_id', '=', activity_id),
                    ('role_category_id', '=', category.id)
                ], order='sequence')
                
                for item in items:
                    for reg in item.item_registration_ids:
                        # 设置行高（以容纳图片）
                        ws_reg.set_row(row, 60)
                        
                        ws_reg.write(row, 0, category.name, cell_format)
                        ws_reg.write(row, 1, item.name, cell_format)
                        ws_reg.write(row, 2, reg.name, cell_format)
                        ws_reg.write(row, 3, reg.introduction or '', cell_format)
                        ws_reg.write(row, 4, reg.speech_intro or '', cell_format)
                        
                        # 插入报名照片
                        if reg.photo_url:
                            try:
                                photo_url = self._get_full_url(reg.photo_url)
                                _logger.info(f'📸 处理报名照片: {photo_url}')
                                
                                if photo_url.startswith('https://'):
                                    import requests
                                    import io
                                    
                                    photo_response = requests.get(photo_url, timeout=10)
                                    if photo_response.status_code == 200:
                                        image_data = io.BytesIO(photo_response.content)
                                        ws_reg.insert_image(row, 5, photo_url, {
                                            'image_data': image_data,
                                            'x_scale': 0.15,
                                            'y_scale': 0.15,
                                            'x_offset': 5,
                                            'y_offset': 5
                                        })
                                        _logger.info(f'✅ 报名照片插入成功')
                                    else:
                                        _logger.warning(f'⚠️ 下载照片失败: {photo_response.status_code}')
                                        ws_reg.write(row, 5, reg.photo_url, cell_format)
                                else:
                                    _logger.info(f'⚠️ 照片URL不是https，写入链接: {photo_url}')
                                    ws_reg.write(row, 5, reg.photo_url, cell_format)
                            except Exception as e:
                                _logger.error(f'❌ 插入报名照片失败: {str(e)}')
                                ws_reg.write(row, 5, reg.photo_url or '', cell_format)
                        
                        # 插入风采照片（最多3张）
                        perf_urls = []
                        if reg.performance_photo_urls:
                            perf_urls = [url.strip() for url in reg.performance_photo_urls.split(',') if url.strip()]
                        
                        for i in range(3):
                            col = 6 + i
                            if i < len(perf_urls):
                                try:
                                    perf_url = self._get_full_url(perf_urls[i])
                                    _logger.info(f'📸 处理风采照片{i+1}: {perf_url}')
                                    
                                    if perf_url.startswith('https://'):
                                        import requests
                                        import io
                                        
                                        perf_response = requests.get(perf_url, timeout=10)
                                        if perf_response.status_code == 200:
                                            perf_image_data = io.BytesIO(perf_response.content)
                                            ws_reg.insert_image(row, col, perf_url, {
                                                'image_data': perf_image_data,
                                                'x_scale': 0.15,
                                                'y_scale': 0.15,
                                                'x_offset': 5,
                                                'y_offset': 5
                                            })
                                            _logger.info(f'✅ 风采照片{i+1}插入成功')
                                        else:
                                            _logger.warning(f'⚠️ 下载风采照片{i+1}失败: {perf_response.status_code}')
                                            ws_reg.write(row, col, perf_urls[i], cell_format)
                                    else:
                                        _logger.info(f'⚠️ 风采照片{i+1}不是https，写入链接')
                                        ws_reg.write(row, col, perf_urls[i], cell_format)
                                except Exception as e:
                                    _logger.error(f'❌ 插入风采照片{i+1}失败: {str(e)}')
                                    ws_reg.write(row, col, perf_urls[i] if i < len(perf_urls) else '', cell_format)
                            else:
                                ws_reg.write(row, col, '', cell_format)
                        
                        status_dict = {'pending': '待审核', 'approved': '已通过', 'rejected': '已拒绝'}
                        ws_reg.write(row, 9, status_dict.get(reg.status, reg.status), cell_format)
                        row += 1
            
            # 设置列宽
            ws_reg.set_column(0, 0, 15)  # 角色分类
            ws_reg.set_column(1, 1, 20)  # 项目名称
            ws_reg.set_column(2, 2, 15)  # 姓名
            ws_reg.set_column(3, 3, 30)  # 自我介绍
            ws_reg.set_column(4, 4, 30)  # 演讲介绍
            ws_reg.set_column(5, 5, 12)  # 报名照片
            ws_reg.set_column(6, 8, 12)  # 风采照片1-3
            ws_reg.set_column(9, 9, 12)  # 状态
            
            workbook.close()
            output.seek(0)
            
            # 返回Excel文件
            from odoo import fields
            from urllib.parse import quote
            
            filename = f'会议报名_{activity.title}_{fields.Datetime.now().strftime("%Y%m%d_%H%M%S")}.xlsx'
            # URL编码文件名以支持中文（RFC 5987）
            filename_encoded = quote(filename)
            
            _logger.info(f'✅ Excel生成成功: {filename}')
            
            return request.make_response(
                output.getvalue(),
                headers=[
                    ('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'),
                    ('Content-Disposition', f"attachment; filename*=UTF-8''{filename_encoded}")
                ]
            )
            
        except Exception as e:
            _logger.error(f'❌ 导出失败: {str(e)}', exc_info=True)
            return request.make_json_response(api_response(False, message=f'导出失败: {str(e)}'))

    @http.route('/api/v1/activities/<int:activity_id>/managers', type='json', auth='public', methods=['POST'], csrf=False, cors='*')
    def add_manager(self, activity_id, **kwargs):
        """添加会议管理员（处理邀请）"""
        try:
            # 验证Token
            token = request.httprequest.headers.get('Authorization', '').replace('Bearer ', '')
            _logger.info(f'👤 POST /activities/{activity_id}/managers: token={token[:20] if token else "无"}...')
            
            if not token:
                return api_response(False, message='请先登录', code=401)
            
            user = request.env['wechat.user'].sudo().search([('token', '=', token)], limit=1)
            
            if not user or not user.check_token(token):
                return api_response(False, message='登录已过期，请重新登录', code=401)
            
            _logger.info(f'💚 Token验证成功: 用户={user.name}, user_id={user.id}')
            
            # 获取会议
            activity = request.env['speech.activity'].sudo().browse(activity_id)
            
            if not activity.exists():
                return api_response(False, message='会议不存在', code=404)
            
            # 检查是否已经是管理员
            if user in activity.manager_ids:
                _logger.info(f'⚠️ 用户已经是管理员')
                return api_response(True, message='您已经是此会议的管理员')
            
            # 检查是否是创建者
            if activity.creator_id.id == user.id:
                _logger.info(f'⚠️ 创建者不需要添加为管理员')
                return api_response(True, message='您是会议创建者，已拥有所有权限')
            
            # 添加为管理员
            activity.sudo().write({
                'manager_ids': [(4, user.id)]  # (4, id) 表示添加关联
            })
            
            _logger.info(f'✅ 添加管理员成功: activity={activity.title}, user={user.name}')
            
            return api_response(True, message=f'您已成为"{activity.title}"的管理员')
            
        except Exception as e:
            _logger.error(f'❌ 添加管理员失败: {str(e)}', exc_info=True)
            return api_response(False, message=f'添加失败: {str(e)}')

